package com.hopes.bizz.risk.statistic.serivce.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hopes.bizz.common.core.util.DateUtils;
import com.hopes.bizz.risk.common.constant.HidDicConstant;
import com.hopes.bizz.risk.common.constant.RiskDicConstant;
import com.hopes.bizz.risk.common.constant.enums.RiskSysDictEnum;
import com.hopes.bizz.risk.control.entity.*;
import com.hopes.bizz.risk.control.service.*;
import com.hopes.bizz.risk.hid.entity.RiskHidHiddenDangerEntity;
import com.hopes.bizz.risk.hid.service.RiskHidHiddenDangerService;
import com.hopes.bizz.risk.hid.vo.RiskHidHiddenDangerStatisticsColumnVo;
import com.hopes.bizz.risk.statistic.serivce.GisService;
import com.hopes.bizz.risk.statistic.vo.*;
import com.hopes.boss.admin.api.entity.SysDictItem;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.common.core.exception.BizException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yumr
 * @Description 一张图
 * @time 2023/8/8 16:34
 */
@Service("gisService")
@RequiredArgsConstructor
public class GisServiceImpl implements GisService {

    private final RiskUnitService riskUnitService;
    private final RiskObjectService riskObjectService;
    private final RiskUnitEventService riskUnitEventService;
    private final RiskMeasureTaskService riskMeasureTaskService;
    private final RiskControlMeasureService riskControlMeasureService;
    private final RiskMeasureTaskRecordService riskMeasureTaskRecordService;

    private final RiskHidHiddenDangerService riskHidHiddenDangerService;

    @Override
    public RiskLayerVO riskLayerData() {
        final RiskLayerVO riskLayerVO = new RiskLayerVO();
        // 风险单元列表
        final List<RiskUnitEntity> riskUnitList = riskUnitService.list(Wrappers.<RiskUnitEntity>lambdaQuery().isNotNull(RiskUnitEntity::getAreaScope));
        if (CollUtil.isNotEmpty(riskUnitList)) {
            riskLayerVO.setUnitList(
                    riskUnitList.parallelStream().map(e ->
                            CoordinateVO.builder().id(e.getId()).name(e.getRiskName()).riskLevel(e.getRiskLevel()).areaScope(e.getAreaScope()).build()
                    ).collect(Collectors.toList()));
        }
        // 风险对象列表
        final List<RiskObjectEntity> riskObjectList = riskObjectService.list(Wrappers.<RiskObjectEntity>lambdaQuery().isNotNull(RiskObjectEntity::getAreaScope));
        if (CollUtil.isNotEmpty(riskObjectList)) {
            riskLayerVO.setObjectList(
                    riskObjectList.parallelStream().map(e ->
                            CoordinateVO.builder().id(e.getId()).name(e.getHazardName()).riskLevel(e.getRiskLevel()).areaScope(e.getAreaScope()).build()
                    ).collect(Collectors.toList()));
        }
        return riskLayerVO;
    }

    @Override
    public RiskCountVO riskCountStatistic() {
        final RiskCountVO riskCountVO = new RiskCountVO();
        riskCountVO.setRiskUnitCount(riskUnitService.count());
        riskCountVO.setRiskObjectCount(riskObjectService.count());
        riskCountVO.setRiskUnitEventCount(riskUnitEventService.count());
        riskCountVO.setRiskControlCount(riskControlMeasureService.count());
        riskCountVO.setRiskTaskRecordCount(riskMeasureTaskRecordService.count());
        riskCountVO.setRiskFinishTaskRecordCount(
                riskMeasureTaskRecordService.count(
                        Wrappers.<RiskMeasureTaskRecordEntity>lambdaQuery()
                                .eq(RiskMeasureTaskRecordEntity::getTaskStatus, RiskDicConstant.HIDDEN_CHECK_TASK_STATUS_FINISH)));
        return riskCountVO;
    }

    @Override
    public RiskLevelCountVO riskLevelStatistic() {
        final List<SysDictItem> riskLevelList = DictResolver.getItemsByType(RiskSysDictEnum.risk_level);
        if (CollUtil.isEmpty(riskLevelList)) {
            throw new BizException("风险等级获取失败！");
        }
        final List<RiskUnitEntity> riskUnitList = riskUnitService.list(
                Wrappers.<RiskUnitEntity>lambdaQuery().isNotNull(RiskUnitEntity::getRiskLevel)
                        .ne(RiskUnitEntity::getRiskLevel, RiskDicConstant.MIN_RISK_LEVEL).select(RiskUnitEntity::getId, RiskUnitEntity::getRiskLevel));

        final List<RiskObjectEntity> riskObjectList = riskObjectService.list(
                Wrappers.<RiskObjectEntity>lambdaQuery().isNotNull(RiskObjectEntity::getRiskLevel)
                        .ne(RiskObjectEntity::getRiskLevel, RiskDicConstant.MIN_RISK_LEVEL).select(RiskObjectEntity::getId, RiskObjectEntity::getRiskLevel));

        final List<RiskUnitEventEntity> riskUnitEventList = riskUnitEventService.list(
                Wrappers.<RiskUnitEventEntity>lambdaQuery().isNotNull(RiskUnitEventEntity::getRiskLevel)
                        .ne(RiskUnitEventEntity::getRiskLevel, RiskDicConstant.MIN_RISK_LEVEL).select(RiskUnitEventEntity::getId, RiskUnitEventEntity::getRiskLevel));

        final RiskLevelCountVO riskLevelCountVO = new RiskLevelCountVO();
        final List<String> riskLevelCollect = riskLevelList.stream().map(SysDictItem::getCode)
                .filter(StrUtil::isNotEmpty).filter(e -> !e.equals(RiskDicConstant.MIN_RISK_LEVEL.toString())).collect(Collectors.toList());
        riskLevelCountVO.setRiskLevelList(riskLevelList);
        riskLevelCountVO.setRiskUnitLevel(buildRiskLevel(riskLevelCollect, riskUnitList, RiskUnitEntity::getRiskLevel));
        riskLevelCountVO.setRiskObjectLevel(buildRiskLevel(riskLevelCollect, riskObjectList, RiskObjectEntity::getRiskLevel));
        riskLevelCountVO.setRiskUnitEventLevel(buildRiskLevel(riskLevelCollect, riskUnitEventList, RiskUnitEventEntity::getRiskLevel));
        return riskLevelCountVO;
    }

    @Override
    public List<RiskControlClassifyVO> riskControlClassify() {
        final List<SysDictItem> workTypeList = DictResolver.getItemsByType(RiskSysDictEnum.risk_work_type);
        final List<SysDictItem> sysDictItemList = DictResolver.getItemsByType(RiskSysDictEnum.risk_control_classify);
        if (CollUtil.isEmpty(workTypeList) || CollUtil.isEmpty(sysDictItemList)) {
            throw new BizException("工作类型分类或者管控措施分类获取失败！");
        }
        // classify 1 分类
        final List<SysDictItem> controlClassifyList = sysDictItemList.parallelStream().filter(e ->
                Objects.nonNull(e.getParentId()) && e.getDictId().equals(e.getParentId())).collect(Collectors.toList());
        // 管控措施集合
        final List<RiskControlMeasureEntity> controlMeasureList = riskControlMeasureService.list(
                Wrappers.<RiskControlMeasureEntity>lambdaQuery().isNotNull(RiskControlMeasureEntity::getClassify1).select(RiskControlMeasureEntity::getId, RiskControlMeasureEntity::getClassify1));
        final Map<String, List<RiskControlMeasureEntity>> listMap = controlMeasureList.stream().filter(e -> Objects.nonNull(e.getClassify1())).collect(Collectors.groupingBy(RiskControlMeasureEntity::getClassify1));

        final List<RiskControlClassifyVO> result = new ArrayList<>();
        for (SysDictItem classify : controlClassifyList) {
            final RiskControlClassifyVO item = new RiskControlClassifyVO();
            item.setClassify(classify.getCode());
            item.setControlIdList(listMap.getOrDefault(classify.getCode(), new ArrayList<>()).stream().map(RiskControlMeasureEntity::getId).collect(Collectors.toList()));
            item.setControlTaskType(buildControlTaskType(workTypeList, item.getControlIdList()));
            result.add(item);
        }
        return result;
    }

    @Override
    public RiskHidHiddenDangerStatisticsColumnVo riskHidTypeInfoYear() {
        final int year = Calendar.getInstance().get(Calendar.YEAR);
        // 1、统计一年的数据
        final Date beginDate = DateUtils.parseDate(year + "-01-01 00:00:00", DateUtils.FORMAT_SECOND);
        final Date endDate = DateUtils.parseDate(year + "-12-31 23:59:59", DateUtils.FORMAT_SECOND);

        final List<RiskHidHiddenDangerEntity> hidHiddenDangerList = riskHidHiddenDangerService.list(
                Wrappers.<RiskHidHiddenDangerEntity>lambdaQuery()
                        .ge(RiskHidHiddenDangerEntity::getReportDate, beginDate).le(RiskHidHiddenDangerEntity::getReportDate, endDate));

        final RiskHidHiddenDangerStatisticsColumnVo res = new RiskHidHiddenDangerStatisticsColumnVo();
        if (CollUtil.isEmpty(hidHiddenDangerList)) {
            return res;
        }

        final List<String> nameList = new ArrayList<>();
        final List<Integer> highLevelNum = new ArrayList<>();
        final List<Integer> normalLevelNum = new ArrayList<>();
        final List<Integer> finishStatusNum = new ArrayList<>();

        // 2、隐患类型分类
        final Map<String, List<RiskHidHiddenDangerEntity>> listMap = hidHiddenDangerList.parallelStream().filter(item ->
                Objects.nonNull(item.getHidTypeStr())).collect(Collectors.groupingBy(RiskHidHiddenDangerEntity::getHidTypeStr));
        for (Map.Entry<String, List<RiskHidHiddenDangerEntity>> entry : listMap.entrySet()) {
            nameList.add(entry.getKey());

            final List<RiskHidHiddenDangerEntity> dangerList = entry.getValue();
            if (CollUtil.isEmpty(dangerList)) {
                highLevelNum.add(0);
                normalLevelNum.add(0);
            } else {
                final Map<Integer, Long> longMap = dangerList.parallelStream().filter(e ->
                        Objects.nonNull(e.getHidLevel())).collect(Collectors.groupingBy(RiskHidHiddenDangerEntity::getHidLevel, Collectors.counting()));
                highLevelNum.add(MapUtil.getInt(longMap, HidDicConstant.DANGER_LEVEL_MAJOR, 0));
                normalLevelNum.add(MapUtil.getInt(longMap, HidDicConstant.DANGER_LEVEL_GENERAL, 0));
            }
            // 3、统计改类型下，已整改的数量
            final long count = dangerList.parallelStream().filter(e ->
                    Objects.nonNull(e.getHidStatus())).filter(e -> e.getHidStatus() >= HidDicConstant.HID_DANGER_STATUS_WAIT_ACCEPTANCE).count();
            finishStatusNum.add(Long.valueOf(count).intValue());
        }

        final RiskHidHiddenDangerStatisticsColumnVo dangerStatisticsColumnVo = new RiskHidHiddenDangerStatisticsColumnVo();
        dangerStatisticsColumnVo.setName(nameList);
        dangerStatisticsColumnVo.setHighLevelNum(highLevelNum);
        dangerStatisticsColumnVo.setNormalLevelNum(normalLevelNum);
        dangerStatisticsColumnVo.setFinishStatusNum(finishStatusNum);

        return dangerStatisticsColumnVo;
    }

    @Override
    public int[] riskHiddenDangerYear() {
        final int year = Calendar.getInstance().get(Calendar.YEAR);
        // 1、统计一年的数据
        final Date beginDate = DateUtils.parseDate(year + "-01-01 00:00:00", DateUtils.FORMAT_SECOND);
        final Date endDate = DateUtils.parseDate(year + "-12-31 23:59:59", DateUtils.FORMAT_SECOND);

        final List<RiskHidHiddenDangerEntity> dangerList = riskHidHiddenDangerService.list(
                Wrappers.<RiskHidHiddenDangerEntity>lambdaQuery()
                        .ge(RiskHidHiddenDangerEntity::getReportDate, beginDate).le(RiskHidHiddenDangerEntity::getReportDate, endDate));

        return groupByMonth(dangerList, RiskHidHiddenDangerEntity::getReportDate);
    }

    @Override
    public RiskTaskRecordVO riskTaskRecordYear() {
        final int year = Calendar.getInstance().get(Calendar.YEAR);
        // 1、统计一年的数据
        final Date beginDate = DateUtils.parseDate(year + "-01-01 00:00:00", DateUtils.FORMAT_SECOND);
        final Date endDate = DateUtils.parseDate(year + "-12-31 23:59:59", DateUtils.FORMAT_SECOND);

        final List<RiskMeasureTaskRecordEntity> taskRecordList = riskMeasureTaskRecordService.list(
                Wrappers.<RiskMeasureTaskRecordEntity>lambdaQuery()
                        .ge(RiskMeasureTaskRecordEntity::getTaskStartTime, beginDate).le(RiskMeasureTaskRecordEntity::getTaskStartTime, endDate)
                        .in(RiskMeasureTaskRecordEntity::getTaskStatus, RiskDicConstant.HIDDEN_CHECK_TASK_STATUS_FINISH, RiskDicConstant.HIDDEN_CHECK_TASK_STATUS_EXPIRE));

        final RiskTaskRecordVO riskTaskRecordVO = new RiskTaskRecordVO();
        if (CollUtil.isEmpty(taskRecordList)) {
            return riskTaskRecordVO;
        }

        final Map<Integer, List<RiskMeasureTaskRecordEntity>> listMap = taskRecordList.parallelStream().filter(e ->
                Objects.nonNull(e.getTaskStatus())).collect(Collectors.groupingBy(RiskMeasureTaskRecordEntity::getTaskStatus));

        riskTaskRecordVO.setExpire(groupByMonth(listMap.get(RiskDicConstant.HIDDEN_CHECK_TASK_STATUS_EXPIRE), RiskMeasureTaskRecordEntity::getTaskStartTime));
        riskTaskRecordVO.setFinish(groupByMonth(listMap.get(RiskDicConstant.HIDDEN_CHECK_TASK_STATUS_FINISH), RiskMeasureTaskRecordEntity::getTaskStartTime));

        return riskTaskRecordVO;
    }

    private <T> int[] groupByMonth(List<T> collection, Function<T, Date> mapper) {
        final int[] array = new int[12];
        if (CollUtil.isEmpty(collection)) {
            return array;
        }
        final Map<Integer, Long> longMap = collection.parallelStream().filter(e ->
                Objects.nonNull(mapper.apply(e))).collect(Collectors.groupingBy(e -> DateUtils.getMonth(mapper.apply(e)), Collectors.counting()));
        longMap.forEach((k, v) -> array[k-1] = v.intValue());
        return array;
    }

    private Map<String, Integer> buildControlTaskType(List<SysDictItem> workTypeList, List<Long> controlIdList) {
        final Map<String, Integer> taskTypeMap = new HashMap<>();
        for (SysDictItem sysDictItem : workTypeList) {
            taskTypeMap.put(sysDictItem.getName(), 0);
        }
        if (CollUtil.isEmpty(controlIdList)) {
            return taskTypeMap;
        }
        final List<RiskMeasureTaskEntity> taskList = riskMeasureTaskService.list(
                Wrappers.<RiskMeasureTaskEntity>lambdaQuery().isNotNull(RiskMeasureTaskEntity::getWorkType).in(RiskMeasureTaskEntity::getRiskControlId, controlIdList).select(RiskMeasureTaskEntity::getId, RiskMeasureTaskEntity::getWorkType));
        if (CollUtil.isEmpty(taskList)) {
            return taskTypeMap;
        }
        final Map<String, Long> listMap = taskList.parallelStream().filter(e -> Objects.nonNull(e.getWorkType())).collect(Collectors.groupingBy(RiskMeasureTaskEntity::getWorkTypeStr, Collectors.counting()));
        for (Map.Entry<String, Integer> entry : taskTypeMap.entrySet()) {
            entry.setValue(listMap.getOrDefault(entry.getKey(), 0L).intValue());
        }
        return taskTypeMap;
    }

    private <T> Map<String, Integer> buildRiskLevel(List<String> riskLevelCollect, List<T> collection, Function<T, Integer> mapper) {
        final Map<String, Integer> riskLevelMap = initResList(riskLevelCollect);
        if (CollUtil.isEmpty(collection)) {
            return riskLevelMap;
        }
        final Map<Integer, Long> listMap = collection.parallelStream().filter(e -> Objects.nonNull(mapper.apply(e))).collect(Collectors.groupingBy(mapper, Collectors.counting()));
        for (Map.Entry<Integer, Long> entry : listMap.entrySet()) {
            riskLevelMap.put(entry.getKey().toString(), entry.getValue().intValue());
        }
        riskLevelMap.put("total", riskLevelMap.values().stream().mapToInt(Integer::intValue).sum());
        return riskLevelMap;
    }

    /**
     * 初始化数据
     * @param riskLevelCollect  风险等级
     * @return                  结果集
     */
    private Map<String, Integer> initResList(List<String> riskLevelCollect) {
        final HashMap<String, Integer> res = new HashMap<>();
        if (CollUtil.isEmpty(riskLevelCollect)) {
            return res;
        }
        riskLevelCollect.forEach(item -> res.put(item, 0));
        res.put("total", 0);
        return res;
    }
}
